import { TableDatas } from './table-datas';
import { Config } from './config';
import { Injectable } from '../decorators/inject';
import { Hook } from './hook';
import { MergeCell } from './merge-cell';
import { TMergeCell } from '../types/common.interface';
import { FillRender } from './fill-render';
import { Cache } from './cache';
import { CellRenderEditManage } from './cell-render-edit-manage';
@Injectable('MergeCellRender')
export class MergeCellRender {
    constructor(
        protected datas: TableDatas,
        protected fillRender: FillRender,
        protected conf: Config,
        protected cache: Cache,
        protected mergeCell: MergeCell,
        protected renderManage: CellRenderEditManage
    ) {

    }
    protected getOriginDrawBoundary(merge: TMergeCell) {
        let vBoundary = this.cache.getRowRangePositionInfo(merge.row, merge.row + merge.rowspan - 1);
        let hBoundary = this.cache.getColRangePositionInfo(merge.col, merge.col + merge.colspan - 1);
        return {
            x: hBoundary.start + this.conf.enlarge,
            y: vBoundary.start + this.conf.enlarge,
            w: hBoundary.end - hBoundary.start - this.conf.enlarge,
            h: vBoundary.end - vBoundary.start - this.conf.enlarge
        }
    }
    protected renderQuadrant1(merges: (TMergeCell&{origin: TMergeCell})[]) {
        for(let _merge of merges) {
            let merge = this.mergeCell.getAfterSplitMergeRectMerge(_merge);
            if(!merge) {
                continue;
            }
            if(merge.colspan !== merge.origin.colspan || merge.rowspan !== merge.origin.rowspan) {
                if(this.conf.freeze.row + 1 !== this.cache.rowBoundary.start && this.conf.freeze.col + 1 !== this.cache.colBoundary.start) {
                    let hInfo = (() => {
                        let rect = this.cache.getColRangePositionInfo(merge.col, merge.col + merge.colspan - 1);
                        return {
                            startX: rect.start,
                            endX: rect.end,
                            paddingRight: this.conf.defaultPadding.right
                        }
                    })();
                    let vInfo = (() => {
                        let rect = this.cache.getRowRangePositionInfo(merge.row, merge.row + merge.rowspan - 1);
                        return {
                            startY: rect.start,
                            endY: rect.end,
                            paddingBottom: this.conf.defaultPadding.bottom
                        }
                    })();
                    const clip = {
                        x: hInfo.startX + this.conf.enlarge,
                        y: vInfo.startY + this.conf.enlarge,
                        w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                        h: vInfo.endY - vInfo.startY - this.conf.enlarge
                    }
                    const opt = {
                        padding: {
                            top: this.conf.defaultPadding.top * this.conf.enlarge,
                            left: this.conf.defaultPadding.left * this.conf.enlarge,
                            bottom: vInfo.paddingBottom * this.conf.enlarge,
                            right: hInfo.paddingRight * this.conf.enlarge
                        }
                    }
                    this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.row, merge.col, opt);
                    return;
                }
            } else {
                let hInfo = (() => {
                    let rect = this.cache.getColRangePositionInfo(merge.col, merge.col + merge.colspan - 1);
                    return {
                        startX: rect.start,
                        endX: rect.end,
                    }
                })();
                let vInfo = (() => {
                    let rect = this.cache.getRowRangePositionInfo(merge.row, merge.row + merge.colspan - 1);
                    return {
                        startY: rect.start,
                        endY: rect.end
                    }
                })();
                const clip = {
                    x: hInfo.startX + this.conf.enlarge,
                    y: vInfo.startY + this.conf.enlarge,
                    w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                    h: vInfo.endY - vInfo.startY - this.conf.enlarge
                }
                const opt = {
                    padding: {
                        top: this.conf.defaultPadding.top * this.conf.enlarge,
                        left: this.conf.defaultPadding.left * this.conf.enlarge,
                        bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                        right: this.conf.defaultPadding.right * this.conf.enlarge
                    }
                }
                this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.row, merge.col, opt)
            }
        }
    }
    protected renderQuadrant2(merges: (TMergeCell&{origin: TMergeCell})[]) {
        for(let _merge of merges) {
            let merge = this.mergeCell.getAfterSplitMergeRectMerge(_merge);
            if(merge === null) {
                continue;
            }
            if(merge.rowspan !== merge.origin.rowspan || merge.colspan !== merge.origin.colspan) {
                if(this.cache.rowBoundary.start !== this.conf.freeze.row + 1) {
                    let vInfo = (() => {
                        let row = merge.row;
                        let rowspan = merge.rowspan;
                        let rect = this.cache.getRowRangePositionInfo(row, row + rowspan - 1);
                        return {
                            startY: rect.start,
                            endY: rect.end
                        }
                    })();
                    if(this.cache.colBoundary.start === this.conf.freeze.col + 1) {
                        let col = merge.origin.col;
                        let colspan = (() => {
                            if(merge.colspan + merge.col - 1 > this.cache.colBoundary.end) {
                                return this.cache.colBoundary.end - col + 1;
                            } else {
                                return merge.origin.colspan;
                            }
                        })();
                        let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                        let hInfo = {
                            startX: rect.start,
                            endX: rect.end
                        }
                        const clip = {
                            x: hInfo.startX + this.conf.enlarge,
                            y: vInfo.startY + this.conf.enlarge,
                            w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                            h: vInfo.endY - vInfo.startY - this.conf.enlarge
                        }
                        const opt = {
                            padding: {
                                top: this.conf.defaultPadding.top * this.conf.enlarge,
                                left: this.conf.defaultPadding.left * this.conf.enlarge,
                                bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                                right: this.conf.defaultPadding.right * this.conf.enlarge
                            }
                        }
                       
                        let rowInstance = this.datas.getRow(merge.row);
                        if(!rowInstance.colIsExist(col)) {
                            return;
                        }
                        this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.origin.row, merge.origin.col, opt)
                    } else {
                        let col = merge.col;
                        let colspan = (() => {
                            if(merge.col + merge.colspan - 1 > this.cache.colBoundary.end) {
                                return this.cache.colBoundary.end - merge.col + 1;
                            }
                            return merge.colspan;
                        })();
                        let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                        let hInfo = {
                            startX: rect.start,
                            endX: rect.end
                        }
                        const clip = {
                            x: hInfo.startX + this.conf.enlarge,
                            y: vInfo.startY + this.conf.enlarge,
                            w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                            h: vInfo.endY - vInfo.startY - this.conf.enlarge
                        }
                        const opt = {
                            padding: {
                                top: this.conf.defaultPadding.top * this.conf.enlarge,
                                left: this.conf.defaultPadding.left * this.conf.enlarge,
                                bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                                right: this.conf.defaultPadding.right * this.conf.enlarge
                            }
                        }
                        this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.row, merge.col, opt)
                    }
                } 
                // else render by 4
            } else {
                const hInfo = (() => {
                    let col = merge.col;
                    let colspan = (() => {
                        if(merge.col + merge.colspan -  1 > this.cache.colBoundary.end) {
                            return this.cache.colBoundary.end - merge.col;
                        } else {
                            return merge.colspan;
                        }
                    })();
                    let rect = this.cache.getColRangePositionInfo(col, colspan + col - 1);
                    return {    
                        startX: rect.start,
                        endX: rect.end
                    }
                })();
                const vInfo = (() => {
                    let row = merge.row;
                    let rowspan = merge.rowspan;
                    let rect = this.cache.getRowRangePositionInfo(row, row + rowspan - 1);
                    return {
                        startY: rect.start,
                        endY: rect.end
                    }
                })();
                const clip = {
                    x: hInfo.startX + this.conf.enlarge,
                    y: vInfo.startY + this.conf.enlarge,
                    w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                    h: vInfo.endY - vInfo.startY - this.conf.enlarge
                }
                const opt = {
                    padding: {
                        top: this.conf.defaultPadding.top * this.conf.enlarge,
                        left: this.conf.defaultPadding.left * this.conf.enlarge,
                        bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                        right: this.conf.defaultPadding.right * this.conf.enlarge
                    }
                }
                this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.row, merge.col, opt)
            }
        }
    }
    protected renderQuadrant3(merges: (TMergeCell&{origin: TMergeCell})[]) {
        for(let _merge of merges) {
            let merge = this.mergeCell.getAfterSplitMergeRectMerge(_merge);
            if(merge === null) {
                continue;
            }
            
            if(merge.rowspan !== merge.origin.rowspan || merge.colspan !== merge.origin.colspan) {
                if(this.conf.freeze.row + 1 === this.cache.rowBoundary.start) {
                    let vInfo = (() => {
                        let row = merge.origin.row;
                        let rowspan = (() => {
                            if(row + merge.origin.rowspan - 1 > this.cache.rowBoundary.end) {
                                return this.cache.rowBoundary.end - row + 1;
                            }
                            return merge.origin.rowspan;
                        })();
                        let padding = this.conf.defaultPadding.top;
                        let rect = this.cache.getRowRangePositionInfo(row, row + rowspan - 1);
                        return {
                            startY: rect.start,
                            endY: rect.end,
                            padding: padding
                        }
                    })();
                    if(this.conf.freeze.col + 1 !== this.cache.colBoundary.start) {
                        let hInfo = (() => {
                            let col = merge.col;
                            let colspan = merge.colspan;
                            let padding = this.conf.defaultPadding.right;
                            let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                            return {
                                startX: rect.start,
                                endX: rect.end,
                                padding: padding
                            }
                        })();
                        const clip = {
                            x: hInfo.startX + this.conf.enlarge,
                            y: vInfo.startY + this.conf.enlarge,
                            w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                            h: vInfo.endY - vInfo.startY - this.conf.enlarge
                        }
                        const opt = {
                            padding: {
                                top: this.conf.defaultPadding.top * this.conf.enlarge,
                                left: this.conf.defaultPadding.left * this.conf.enlarge,
                                bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                                right: this.conf.defaultPadding.right * this.conf.enlarge
                            }
                        }
                        return this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.origin.row, merge.origin.col, opt);
                    } // to 4

                } else {
                    if(this.conf.freeze.col + 1 !== this.cache.colBoundary.start) {
                        let vInfo = (() => {
                            let row = merge.row;
                            let rowspan = merge.rowspan;
                            let rect = this.cache.getRowRangePositionInfo(row, row + rowspan - 1);
                            return {
                                startY: rect.start,
                                endY: rect.end
                            }
                        })();
                        let hInfo = (() => {
                            let col = merge.col;
                            let colspan = merge.colspan;
                            let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                            return {
                                startX: rect.start,
                                endX: rect.end
                            }
                        })();
                        const clip = {
                            x: hInfo.startX + this.conf.enlarge,
                            y: vInfo.startY + this.conf.enlarge,
                            w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                            h: vInfo.endY - vInfo.startY - this.conf.enlarge
                        }
                        const opt = {
                            padding: {
                                top: this.conf.defaultPadding.top * this.conf.enlarge,
                                left: this.conf.defaultPadding.left * this.conf.enlarge,
                                bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                                right: this.conf.defaultPadding.right * this.conf.enlarge
                            }
                        }
                        return this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.origin.row, merge.origin.col, opt);
                    }
                }
            }
        }
    }
    protected renderQuadrant4(merges: (TMergeCell&{origin: TMergeCell})[]) {
        for(let _merge of merges) {
            let merge = this.mergeCell.getAfterSplitMergeRectMerge(_merge);
            if(merge === null) {
                continue;
            }
            
            if(merge.rowspan !== merge.origin.rowspan || merge.colspan !== merge.origin.colspan) {
                let vInfo = (() => {
                    if(this.conf.freeze.row + 1 === this.cache.rowBoundary.start) {
                        let row = merge.origin.row;
                        let rowspan = merge.origin.rowspan;
                        if(row + rowspan - 1 > this.cache.rowBoundary.end) {
                            rowspan = this.cache.rowBoundary.end - row + 1;
                        }
                        let rect = this.cache.getRowRangePositionInfo(row , row + rowspan - 1);
                        return {
                            startY: rect.start,
                            endY: rect.end
                        }
                    } else {
                        let row = merge.row;
                        let rowspan = merge.rowspan;
                        if(row + rowspan - 1 > this.cache.rowBoundary.end) {
                            rowspan = this.cache.rowBoundary.end - row + 1;
                        }
                        let rect = this.cache.getRowRangePositionInfo(row, row + rowspan - 1);
                        return {
                            startY: rect.start,
                            endY: rect.end
                        }
                    }          
                })();
                let hInfo = (() => {
                    if(this.conf.freeze.col + 1 === this.cache.colBoundary.start) {
                        let col = merge.origin.col;
                        let colspan = merge.origin.colspan;
                        if(col + colspan - 1 > this.cache.colBoundary.end) {
                            colspan = this.cache.colBoundary.end - col + 1;
                        }
                        let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                        return {
                            startX: rect.start,
                            endX: rect.end
                        }
                    } else {
                        let col = merge.col;
                        let colspan = merge.colspan;
                        if(col + colspan - 1 > this.cache.colBoundary.end) {
                            colspan = this.cache.colBoundary.end - col + 1;
                        }
                        let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                        return {
                            startX: rect.start,
                            endX: rect.end
                        }
                    }
                })();
                const clip = {
                    x: hInfo.startX + this.conf.enlarge,
                    y: vInfo.startY + this.conf.enlarge,
                    w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                    h: vInfo.endY - vInfo.startY - this.conf.enlarge
                }
                const opt = {
                    padding: {
                        top: this.conf.defaultPadding.top * this.conf.enlarge,
                        left: this.conf.defaultPadding.left * this.conf.enlarge,
                        bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                        right: this.conf.defaultPadding.right * this.conf.enlarge
                    }
                }
                this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.origin.row, merge.origin.col, opt);
            } else {
                let hInfo = (() => {
                    let col = merge.col;
                    let colspan = merge.colspan;
                    if(col + colspan - 1 > this.cache.colBoundary.end) {
                        colspan = this.cache.colBoundary.end - col + 1;
                    }
                    let rect = this.cache.getColRangePositionInfo(col, col + colspan - 1);
                    return {
                        startX: rect.start,
                        endX: rect.end
                    }
                })();
                let vInfo = (() => {
                    let row = merge.row;
                    let rowspan = merge.rowspan;
                    if(row + rowspan - 1 > this.cache.rowBoundary.end) {
                        rowspan = this.cache.rowBoundary.end - row + 1;
                    }
                    let rect = this.cache.getRowRangePositionInfo(row, row + rowspan - 1);
                    return {
                        startY: rect.start,
                        endY: rect.end
                    }
                })();
                const clip = {
                    x: hInfo.startX + this.conf.enlarge,
                    y: vInfo.startY + this.conf.enlarge,
                    w: hInfo.endX - hInfo.startX - this.conf.enlarge,
                    h: vInfo.endY - vInfo.startY - this.conf.enlarge
                }
                const opt = {
                    padding: {
                        top: this.conf.defaultPadding.top * this.conf.enlarge,
                        left: this.conf.defaultPadding.left * this.conf.enlarge,
                        bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                        right: this.conf.defaultPadding.right * this.conf.enlarge
                    }
                }
                this.renderQuadrantMergeCell(clip, this.getOriginDrawBoundary(merge.origin), merge.origin.row, merge.origin.col, opt);
            }
        }
    }
    protected renderQuadrantMergeCell(clip: TRect, originDrawBoundary: TRect, row: number, col: number, opt?: {padding: {top: number, right: number, bottom: number, left: number}}) {
        if(!this.datas.rowIsExist(row)) {
            return;
        }
        let rowInstance = this.datas.getRow(row);
        if(!rowInstance.colIsExist(col)) {
            return;
        }
        let cell = rowInstance.getCell(col);
        if(cell.fill) {
            let x = clip.x;
            let y = clip.y;
            let w = clip.w;
            let h = clip.h;
            this.fillRender.addFill({x, y}, {w, h: h}, cell.fill.background.color);
        }
    }
    public render() {
        let newMerges: any[] = [];
        for(let item of this.mergeCell.mergeCells) {
            let tempMerges: (TMergeCell& {q?: number, origin?:TMergeCell})[] = this.mergeCell.spliteMerge(item);
            for(let tempMerge of tempMerges) {
                tempMerge.q = this.mergeCell.getAfterSplitMergeQuadrant(tempMerge);
                tempMerge.origin = item;
                newMerges.push(tempMerge);
            }
        }
        this.renderQuadrant1(newMerges.filter(item => item.q === 1));
        this.renderQuadrant2(newMerges.filter(item => item.q === 2));
        this.renderQuadrant3(newMerges.filter(item => item.q === 3));
        this.renderQuadrant4(newMerges.filter(item => item.q === 4));
    }
}